﻿// Decompiled with JetBrains decompiler
// Type: MCM.LightInject.EmitterExtensions
// Assembly: MCMv5, Version=5.10.2.0, Culture=neutral, PublicKeyToken=null
// MVID: 7AB326B9-B2B4-41C2-9177-68E944071101
// Assembly location: D:\steam\steamapps\workshop\content\261550\2859238197\bin\Win64_Shipping_Client\MCMv5.dll

using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Emit;

#nullable disable
namespace MCM.LightInject
{
  [ExcludeFromCodeCoverage]
  internal static class EmitterExtensions
  {
    public static void UnboxOrCast(this IEmitter emitter, Type type)
    {
      if (emitter.StackType == (Type) null || type == typeof (bool) && emitter.StackType == typeof (int) || type == typeof (byte) && emitter.StackType == typeof (int) || type == typeof (sbyte) && emitter.StackType == typeof (int) || type == typeof (short) && emitter.StackType == typeof (int) || type == typeof (ushort) && emitter.StackType == typeof (int) || type == typeof (uint) && emitter.StackType == typeof (int) || type == typeof (ulong) && emitter.StackType == typeof (long) || type.GetTypeInfo().IsEnum || type.GetTypeInfo().IsAssignableFrom(emitter.StackType.GetTypeInfo()))
        return;
      emitter.Emit(type.GetTypeInfo().IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type);
    }

    public static void PushConstant(this IEmitter emitter, int index, Type type)
    {
      emitter.PushConstant(index);
      emitter.UnboxOrCast(type);
    }

    public static void PushConstant(this IEmitter emitter, int index)
    {
      emitter.PushArgument(0);
      emitter.Push(index);
      emitter.PushArrayElement();
    }

    public static void PushArrayElement(this IEmitter emitter) => emitter.Emit(OpCodes.Ldelem_Ref);

    public static void PushArguments(this IEmitter emitter, ParameterInfo[] parameters)
    {
      LocalBuilder localBuilder = emitter.DeclareLocal(typeof (object[]));
      emitter.Emit(OpCodes.Ldarg_0);
      emitter.Emit(OpCodes.Ldarg_0);
      emitter.Emit(OpCodes.Ldlen);
      emitter.Emit(OpCodes.Conv_I4);
      emitter.Emit(OpCodes.Ldc_I4_1);
      emitter.Emit(OpCodes.Sub);
      emitter.Emit(OpCodes.Ldelem_Ref);
      emitter.Emit(OpCodes.Castclass, typeof (object[]));
      emitter.Emit(OpCodes.Stloc, localBuilder);
      for (int index = 0; index < parameters.Length; ++index)
      {
        emitter.Emit(OpCodes.Ldloc, localBuilder);
        emitter.Emit(OpCodes.Ldc_I4, index);
        emitter.Emit(OpCodes.Ldelem_Ref);
        emitter.Emit(parameters[index].ParameterType.GetTypeInfo().IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, parameters[index].ParameterType);
      }
    }

    public static void Call(this IEmitter emitter, MethodInfo methodInfo)
    {
      emitter.Emit(OpCodes.Callvirt, methodInfo);
    }

    public static void New(this IEmitter emitter, ConstructorInfo constructorInfo)
    {
      emitter.Emit(OpCodes.Newobj, constructorInfo);
    }

    public static void Push(this IEmitter emitter, LocalBuilder localBuilder)
    {
      int localIndex = localBuilder.LocalIndex;
      switch (localIndex)
      {
        case 0:
          emitter.Emit(OpCodes.Ldloc_0);
          break;
        case 1:
          emitter.Emit(OpCodes.Ldloc_1);
          break;
        case 2:
          emitter.Emit(OpCodes.Ldloc_2);
          break;
        case 3:
          emitter.Emit(OpCodes.Ldloc_3);
          break;
        default:
          if (localIndex <= (int) byte.MaxValue)
          {
            emitter.Emit(OpCodes.Ldloc_S, (byte) localIndex);
            break;
          }
          emitter.Emit(OpCodes.Ldloc, localIndex);
          break;
      }
    }

    public static void PushArgument(this IEmitter emitter, int index)
    {
      switch (index)
      {
        case 0:
          emitter.Emit(OpCodes.Ldarg_0);
          break;
        case 1:
          emitter.Emit(OpCodes.Ldarg_1);
          break;
        case 2:
          emitter.Emit(OpCodes.Ldarg_2);
          break;
        case 3:
          emitter.Emit(OpCodes.Ldarg_3);
          break;
        default:
          if (index <= (int) byte.MaxValue)
          {
            emitter.Emit(OpCodes.Ldarg_S, (byte) index);
            break;
          }
          emitter.Emit(OpCodes.Ldarg, index);
          break;
      }
    }

    public static void Store(this IEmitter emitter, LocalBuilder localBuilder)
    {
      int localIndex = localBuilder.LocalIndex;
      switch (localIndex)
      {
        case 0:
          emitter.Emit(OpCodes.Stloc_0);
          break;
        case 1:
          emitter.Emit(OpCodes.Stloc_1);
          break;
        case 2:
          emitter.Emit(OpCodes.Stloc_2);
          break;
        case 3:
          emitter.Emit(OpCodes.Stloc_3);
          break;
        default:
          if (localIndex <= (int) byte.MaxValue)
          {
            emitter.Emit(OpCodes.Stloc_S, (byte) localIndex);
            break;
          }
          emitter.Emit(OpCodes.Stloc, localIndex);
          break;
      }
    }

    public static void PushNewArray(this IEmitter emitter, Type elementType)
    {
      emitter.Emit(OpCodes.Newarr, elementType);
    }

    public static void Push(this IEmitter emitter, int value)
    {
      switch (value)
      {
        case 0:
          emitter.Emit(OpCodes.Ldc_I4_0);
          break;
        case 1:
          emitter.Emit(OpCodes.Ldc_I4_1);
          break;
        case 2:
          emitter.Emit(OpCodes.Ldc_I4_2);
          break;
        case 3:
          emitter.Emit(OpCodes.Ldc_I4_3);
          break;
        case 4:
          emitter.Emit(OpCodes.Ldc_I4_4);
          break;
        case 5:
          emitter.Emit(OpCodes.Ldc_I4_5);
          break;
        case 6:
          emitter.Emit(OpCodes.Ldc_I4_6);
          break;
        case 7:
          emitter.Emit(OpCodes.Ldc_I4_7);
          break;
        case 8:
          emitter.Emit(OpCodes.Ldc_I4_8);
          break;
        default:
          if (value > -129 && value < 128)
          {
            emitter.Emit(OpCodes.Ldc_I4_S, (sbyte) value);
            break;
          }
          emitter.Emit(OpCodes.Ldc_I4, value);
          break;
      }
    }

    public static void Cast(this IEmitter emitter, Type type)
    {
      emitter.Emit(OpCodes.Castclass, type);
    }

    public static void Return(this IEmitter emitter) => emitter.Emit(OpCodes.Ret);
  }
}
